package server.connector.http;

import org.apache.catalina.util.StringManager;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;

public class SocketInputStream extends InputStream {
    //输入流
    protected InputStream is;
    //缓冲区
    protected byte[] buffer;
    //缓冲区有效数据大小
    protected int length;
    //指向即将要读的元素
    protected int pos;
    protected static StringManager sm = StringManager.getManager(Constants.PACKAGE);
    //构造器
    public SocketInputStream(InputStream is, int bufferSize) {
        this.is = is;
        this.buffer = new byte[bufferSize];
    }

    //解析请求行
    public void readRequestLine(HttpRequestLine requestLine) throws IOException {
        //如果requestLine存过请求行数据，则复位清空
        if (requestLine.methodLength != 0) {
            requestLine.reset();
        }
        //跳过空行
        skipBlankLine();
        //读请求方法
        readMethod(requestLine);
        //读uri
        readUri(requestLine);
        //读协议版本
        readProtocol(requestLine);
    }
    //跳过空行
    private void skipBlankLine() throws IOException {
        int c;
        do {
            c = read();
            if (c == -1) {
                throw  new EOFException(sm.getString("requestStream.readline.error"));
            }
        } while (c == '\r' || c == '\n');
        pos--;

    }
    //读请求方法
    private void readMethod(HttpRequestLine requestLine) throws IOException{
        int maxLength = requestLine.method.length;
        int readCount = 0;
        while (true) {
            int c = read();
            //读到空格 解析请求方法结束
            if (c == ' ') {
                requestLine.methodLength = readCount;
                return;
            } else if (c == -1) {
                throw new IOException(sm.getString("requestStream.readline.error"));
            }
            //如果当前requestLine的method数组存不下数据，扩展
            if (readCount >= maxLength) {
                if (maxLength * 2 <= HttpRequestLine.MAX_METHOD_SIZE) {
                    maxLength = maxLength * 2;
                    char[] newMethod = new char[maxLength];
                    System.arraycopy(requestLine.method, 0, newMethod, 0, requestLine.method.length);
                    requestLine.method = newMethod;
                } else {
                    throw new IOException(sm.getString("requestStream.readline.toolong"));
                }
            }
            //读取数据
            requestLine.method[readCount++] = (char)c;

        }
    }
    //读uri
    private void readUri(HttpRequestLine requestLine) throws IOException {
        int maxLength = requestLine.uri.length;
        int readCount = 0;
        while (true) {
            int c = read();
            //读到空格 解析uri结束
            if (c == ' ') {
                requestLine.uriLength = readCount;
                return;
            } else if (c == -1) {
                throw new IOException(sm.getString("requestStream.readline.error"));
            }
            //如果当前requestLine的uri数组存不下数据，扩展
            if (readCount >= maxLength) {
                if (maxLength * 2 <= HttpRequestLine.MAX_URI_SIZE) {
                    maxLength = maxLength * 2;
                    char[] newUri = new char[maxLength];
                    System.arraycopy(requestLine.uri, 0, newUri, 0, requestLine.uri.length);
                    requestLine.uri = newUri;
                } else {
                    throw new IOException(sm.getString("requestStream.readline.toolong"));
                }
            }
            //读取数据
            requestLine.uri[readCount++] = (char)c;
        }
    }
    //读协议版本
    private void readProtocol(HttpRequestLine requestLine) throws IOException {
        int maxLength = requestLine.protocol.length;
        int readCount = 0;
        while (true) {
            int c = read();
            //读到空格 解析uri结束
            if (c == '\r') {
                continue;
            } else if (c == '\n') {
                requestLine.protocolLength = readCount;
                return;
            }  else if (c == -1) {
                throw new IOException(sm.getString("requestStream.readline.error"));
            }
            //如果当前requestLine的protocol数组存不下数据，扩展
            if (readCount >= maxLength) {
                if (maxLength * 2 <= HttpRequestLine.MAX_PROTOCOL_SIZE) {
                    maxLength = maxLength * 2;
                    char[] newProtocol = new char[maxLength];
                    System.arraycopy(requestLine.protocol, 0, newProtocol, 0, requestLine.protocol.length);
                    requestLine.protocol = newProtocol;
                } else {
                    throw new IOException(sm.getString("requestStream.readline.toolong"));
                }
            }
            //读取数据
            requestLine.protocol[readCount++] = (char)c;
        }
    }

    //读一个请求头到header中
    //如果请求头读完，header的nameLength和valueLength都是0
    public void readHeader(HttpHeader header) throws IOException {
        //如果header中存过数据，则复位清空
        if (header.nameLength != 0) {
            header.reset();
        }
        //检查空行 读到空行说明头部已将读完
        int c = read();
        if (c == '\r' || c == '\n') {
            if (c == '\r') {
                read(); //跳过\n
            }
            header.nameLength = 0;
            header.valueLength = 0;
            return;
        } else {
            pos--;
        }
        //读name
        readName(header);
        readValue(header);

    }
    //读name
    private void readName(HttpHeader header) throws IOException {
        int maxLength = header.name.length;
        int readCount = 0;
        while (true) {
            int c = read();
            //读到: 结束解析name
            if (c == ':') {
                header.nameLength = readCount;
                break;
            } else if (c == -1) {
                throw new IOException(sm.getString("requestStream.readline.error"));
            }
            //如果当前header的name数组存不下数据，扩展
            if (readCount >= maxLength) {
                if (maxLength * 2 <= HttpHeader.MAX_NAME_SIZE) {
                    maxLength = maxLength * 2;
                    char[] newName = new char[maxLength];
                    System.arraycopy(header.name, 0, newName, 0, header.name.length);
                    header.name = newName;
                } else {
                    throw new IOException(sm.getString("requestStream.readline.toolong"));
                }
            }
            //大写转小写
            if (c >= 'A' && c <= 'Z') {
                c = c - ('A' - 'a');
            }
            //读取数据
            header.name[readCount++] = (char)c;
        }
    }
    //读value
    private void readValue(HttpHeader header) throws IOException {
        int maxLength = header.value.length;
        int readCount = 0;
        //跳过空格
        while (true) {
            int c = read();
            if (c == -1) {
                throw new IOException(sm.getString("requestStream.readline.error"));
            } else if (c == ' ' || c == '\t') {

            } else {
                pos--;
                break;
            }
        }
        //开始读value
        while (true) {
            //读到\r\n 结束解析value
            int c = read();
            if (c == '\r') {
                continue;
            } else if (c == '\n') {
                header.valueLength = readCount;
                return;
            } else if (c == -1) {
                throw new IOException(sm.getString("requestStream.readline.error"));
            }
            if (readCount >= maxLength) {
                if (maxLength * 2 <= HttpHeader.MAX_VALUE_SIZE) {
                    maxLength = maxLength * 2;
                    char[] newValue = new char[maxLength];
                    System.arraycopy(header.value, 0, newValue, 0, header.value.length);
                    header.value = newValue;
                } else {
                    throw new IOException(sm.getString("requestStream.readline.toolong"));
                }
            }
            //读取数据
            header.value[readCount++] = (char)c;
        }
    }
    @Override
    public int read() throws IOException {
        //如果缓冲区数据读完，重新从输入流读数据到缓冲区
        if (pos >= length) {
            fill();
            if (length <= 0)
                return -1;
        }
        return buffer[pos++] & 0xff;
    }
    //从输入流中读数据到缓冲区
    protected void fill() throws IOException {
        this.length = is.read(buffer);
        this.pos = 0;
    }
    @Override
    public int available() throws IOException {
        return (length - pos) + is.available();
    }
    @Override
    public void close() throws IOException {
        if (is != null)
            is.close();
        is = null;
        buffer = null;
    }
}
